package si.banst.tecajnice.ejb;

import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.Schedule;
import javax.ejb.Schedules;
import javax.ejb.SessionContext;
import javax.ejb.Singleton;
import javax.interceptor.Interceptors;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

import si.banst.tecajnice.ejb.napake.NapakaPriPrevzemu;
import si.banst.tecajnice.ejb.prestrezniki.SledenjeZahtevam;
import si.banst.tecajnice.entitete.StatusAktivnosti;
import si.banst.tecajnice.entitete.Tecaj;
import si.banst.tecajnice.entitete.TecajID;
import si.banst.tecajnice.entitete.Tecajnica;
import si.banst.tecajnice.entitete.TecajnicaID;
import si.banst.tecajnice.entitete.Valuta;
import si.banst.tecajnice.entitete.VrstaTecajnice;
import si.banst.tecajnice.util.DateUtil;
import si.bsi.tecajnice.arhiv.DtecBS;

/**
 * Session Bean implementation class TecajniceBSiArhivBean
 */
@Singleton
@Interceptors(SledenjeZahtevam.class)
@RolesAllowed({ "OdgovorniReferent", "ReferentZaPreracun" })
public class TecajniceBSiBean implements TecajniceBSiBeanLocal {

	private static final Logger logger = Logger
			.getLogger(TecajniceBSiBean.class.getName());

	private static final String NASLOV_XML_ARHIVA_TECAJNIC = "http://www.bsi.si/_data/tecajnice/dtecbs-l.xml";
	private static final String NASLOV_XML_DNEVNE_TECAJNICE = "http://www.bsi.si/_data/tecajnice/dtecbs.xml";

	@Resource
	private SessionContext sessionContext;

	@EJB
	private TecajniceBeanLocal tecajniceBean;

	@EJB
	private ValuteBeanLocal valuteBean;

	private Date casZadnjePrevzeteTecajnice;

	private VrstaTecajnice vrstaTecajniceBSi;

	/**
	 * Default constructor.
	 */
	public TecajniceBSiBean() {
		super();
	}

	@PostConstruct
	public void init() {
		try {
			logger.fine("Inicializiram referenco na vrsto tečajnice BSi.");
			vrstaTecajniceBSi = tecajniceBean.vrniVrstoTecajniceBSi();

			logger.fine("Nastavljam čas zadnje prevzete tečajnice");
			Tecajnica zadnjaPrevzetaTecajnica = tecajniceBean
					.vrniZadnjoTecajnico(vrstaTecajniceBSi
							.getSifraVrsteTecajnice());
			if (zadnjaPrevzetaTecajnica != null) {
				casZadnjePrevzeteTecajnice = zadnjaPrevzetaTecajnica.getId()
						.getDatumTecajnice();
				casZadnjePrevzeteTecajnice = DateUtil
						.nastaviCasNaPolnoc(casZadnjePrevzeteTecajnice);
			}

		} catch (Exception e) {
			logger.severe("Napaka pri inicializaciji" + e.getMessage());
			throw new EJBException(e);
		}
	}

	@Schedules({ @Schedule(hour = "*"),
			@Schedule(hour = "14-16", minute = "*/10") })
	@PermitAll
	public void casovniPrevzemTecajniceBSi() {
		logger.info("Začenjam poskus avtomatiziranega prevzema tečajnic Banke Slovenije.");
		try {
			if (casZadnjePrevzeteTecajnice != null
					&& casZadnjePrevzeteTecajnice.compareTo(DateUtil
							.nastaviCasNaPolnoc(new Date())) == 0) {
				logger.fine("Tečajnica je že bila prevzeta. ");
			} else if (prevzemiTecajnicoBSi() != null) {
				casZadnjePrevzeteTecajnice = DateUtil
						.nastaviCasNaPolnoc(new Date());
				logger.info("Tečajnica uspešno prevzeta.");
			}
		} catch (Exception e) {
			logger.severe("Napaka pri avtomatiziranem prevzemu tečajnice."
					+ e.getMessage());
		}
	}

	@Override
	public Tecajnica prevzemiTecajnicoBSi() throws NapakaPriPrevzemu {

		try {
			logger.info("Prevzemam tecajnico Banke Slovenije z XML");
			JAXBContext jaxbContext = JAXBContext
					.newInstance("si.bsi.tecajnice.dnevne");
			Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
			logger.fine("Pretvarjam XML zapis s povezave "
					+ NASLOV_XML_DNEVNE_TECAJNICE);
			si.bsi.tecajnice.dnevne.DtecBS dtecBS = (si.bsi.tecajnice.dnevne.DtecBS) unmarshaller
					.unmarshal(new URL(NASLOV_XML_DNEVNE_TECAJNICE)
							.openStream());
			si.bsi.tecajnice.dnevne.DtecBS.Tecajnica tecajnicaBSi = dtecBS
					.getTecajnica();

			if (tecajnicaBSi == null)
				throw new NapakaPriPrevzemu("Prevzeta tečajnica je null");

			logger.fine("Tecajnica prevzeta iz XML oblike za datum "
					+ tecajnicaBSi.getDatum());

			logger.fine("Začenjam pretvorbo tečajnice.");
			TecajnicaID tecajnicaID = new TecajnicaID();
			tecajnicaID.setDatumTecajnice(tecajnicaBSi.getDatum()
					.toGregorianCalendar().getTime());
			tecajnicaID.setSifraVrsteTecajnice(vrstaTecajniceBSi
					.getSifraVrsteTecajnice());

			logger.fine("Preverjam če tečajnica že obstaja.");
			Tecajnica tecajnica = tecajniceBean.vrniTecajnico(tecajnicaID);

			if (tecajnica == null) {
				tecajnica = new Tecajnica();
				tecajnica.setId(tecajnicaID);
				tecajnica.setDatumCasPreracuna(new Date());
				tecajnica.setReferentZaPreracun(sessionContext
						.getCallerPrincipal().getName());
				tecajnica.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
				tecajnica.setVrstaTecajnice(vrstaTecajniceBSi);
				logger.fine("Zapisujem prevzeto tečajnico za datum "
						+ tecajnicaID.getDatumTecajnice());
				tecajniceBean.zapisiTecajnico(tecajnica);
			}

			for (si.bsi.tecajnice.dnevne.DtecBS.Tecajnica.Tecaj tecajbsi : tecajnicaBSi
					.getTecaj()) {

				logger.fine("Iščem valuto za zapis tečaja.");

				Valuta valuta = valuteBean.vrniValuto(Integer.parseInt(tecajbsi
						.getSifra()));

				if (valuta == null) {
					logger.fine("Valuta še ne obstaja. Vstavljam novo valuto.");
					valuta = new Valuta();
					valuta.setSifraValute(Integer.parseInt(tecajbsi.getSifra()));
					valuta.setDatumCasSpremembe(new Date());
					valuta.setNazivDrzave("Drzava" + tecajbsi.getOznaka());
					valuta.setNazivValute("Valuta" + tecajbsi.getOznaka());
					valuta.setOznakaDrzave("D" + tecajbsi.getOznaka());
					valuta.setOznakaValute(tecajbsi.getOznaka());
					valuta.setReferent(sessionContext.getCallerPrincipal()
							.getName());
					valuta.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
					valuteBean.zapisiValuto(valuta);
					logger.fine("Valuta zapisana " + valuta.getOznakaValute());
				}

				logger.fine("Pretvarjam tečaj " + tecajbsi.getOznaka());
				TecajID tecajID = new TecajID();
				tecajID.setSifraVrsteTecajnice(vrstaTecajniceBSi
						.getSifraVrsteTecajnice());
				tecajID.setSifraValute(valuta.getSifraValute());
				tecajID.setDatumTecajnice(tecajnicaID.getDatumTecajnice());

				Tecaj tecaj = tecajniceBean.vrniTecaj(tecajID);

				if (tecaj == null) {
					logger.fine("Tečaj še ne obstaja. Vstavljam nov tečaj.");
					tecaj = new Tecaj();
					tecaj.setId(tecajID);
					tecaj.setDatumCasSpremembe(new Date());
					tecaj.setEnotaTecaja(new BigDecimal(1));
					tecaj.setSrednjiTecaj(tecajbsi.getValue());
					if (tecaj.getSrednjiTecaj() == null)
						throw new NapakaPriPrevzemu("Vrednost tečaja je null");
					tecaj.setReferent(sessionContext.getCallerPrincipal()
							.getName());
					tecaj.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
					tecaj.setTecajnica(tecajnica);
					tecaj.setValuta(valuta);
					logger.fine("Zapisujem tečaj za valuto "
							+ tecaj.getValuta().getOznakaValute());
					tecajniceBean.zapisiTecaj(tecaj);
				} else if (tecaj.getSrednjiTecaj().compareTo(
						tecajbsi.getValue()) != 0) {
					logger.fine("Vrednost obstoječega tečaja se razlikuje od prevzete vrednosti.");
					tecaj.setSrednjiTecaj(tecajbsi.getValue());
					logger.fine("Posodabljam tečaj na novo vrednost");
					tecajniceBean.posodobiTecaj(tecaj);
				}

			}
			logger.fine("Tečajnica pretvorjena");

			return tecajnica;

		} catch (Exception e) {
			logger.severe("Napaka pri prevzemu tecajnice BSi. "
					+ e.getMessage());
			throw new NapakaPriPrevzemu("Napaka pri prevzemu tecajnice BSi.", e);
		}
	}

	@Override	
	@RolesAllowed({ "OdgovorniReferent" })
	public List<Tecajnica> prevzemiArhivTecajnicBSi(int leto)
			throws NapakaPriPrevzemu {

		try {
			JAXBContext jaxbContext = JAXBContext
					.newInstance("si.bsi.tecajnice.arhiv");
			Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
			logger.fine("Pretvarjam XML vsebinos povezave "
					+ NASLOV_XML_ARHIVA_TECAJNIC);
			DtecBS dtecBS = (DtecBS) unmarshaller.unmarshal(new URL(
					NASLOV_XML_ARHIVA_TECAJNIC).openStream());

			int steviloTecajnicVArhivuBSi = dtecBS.getTecajnica().size();
			int steviloNovoZapisanihTecajnic = 0;
			int steviloTecajevVArhivu = 0;
			int steviloPosodobljenihTecajev = 0;
			int steviloNovoZapisanihTecajev = 0;
			int steviloZapisanihValut = 0;

			logger.info("Prevzemam arhiv tečajnic Banke Slovenije. Arhiv vsebuje "
					+ steviloTecajnicVArhivuBSi + " tečajnic");

			List<Tecajnica> seznamPrevzetihTecajnic = new ArrayList<Tecajnica>();

			for (si.bsi.tecajnice.arhiv.DtecBS.Tecajnica tecajnicabsi : dtecBS
					.getTecajnica()) {
				if (leto != 0 && tecajnicabsi.getDatum().getYear() != leto)
					continue;

				logger.fine("Pretvarjam tečajnico za datum "
						+ tecajnicabsi.getDatum());
				TecajnicaID tecajnicaID = new TecajnicaID();
				tecajnicaID.setDatumTecajnice(tecajnicabsi.getDatum()
						.toGregorianCalendar().getTime());
				tecajnicaID.setSifraVrsteTecajnice(vrstaTecajniceBSi
						.getSifraVrsteTecajnice());

				logger.fine("Preverjam če tečajnica že obstaja.");
				Tecajnica tecajnica = tecajniceBean.vrniTecajnico(tecajnicaID);

				if (tecajnica == null) {
					tecajnica = new Tecajnica();
					tecajnica.setId(tecajnicaID);
					tecajnica.setDatumCasPreracuna(new Date());
					tecajnica.setReferentZaPreracun(sessionContext
							.getCallerPrincipal().getName());
					tecajnica.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
					tecajnica.setVrstaTecajnice(vrstaTecajniceBSi);
					logger.fine("Zapisujem prevzeto tečajnico za datum "
							+ tecajnicaID.getDatumTecajnice());
					tecajniceBean.zapisiTecajnico(tecajnica);
					seznamPrevzetihTecajnic.add(tecajnica);
					steviloNovoZapisanihTecajnic++;
				}

				for (si.bsi.tecajnice.arhiv.DtecBS.Tecajnica.Tecaj tecajbsi : tecajnicabsi
						.getTecaj()) {
					steviloTecajevVArhivu++;

					logger.fine("Pretvarjam tečaj " + tecajbsi.getOznaka());
					logger.fine("Iščem valuto za zapis tečaja.");

					Valuta valuta = valuteBean.vrniValuto(Integer
							.parseInt(tecajbsi.getSifra()));

					if (valuta == null) {
						logger.fine("Valuta še ne obstaja. Vstavljam novo valuto. ");
						valuta = new Valuta();
						valuta.setSifraValute(Integer.parseInt(tecajbsi
								.getSifra()));
						valuta.setDatumCasSpremembe(new Date());
						valuta.setNazivDrzave("Drzava" + tecajbsi.getOznaka());
						valuta.setNazivValute("Valuta" + tecajbsi.getOznaka());
						valuta.setOznakaDrzave("D" + tecajbsi.getOznaka());
						valuta.setOznakaValute(tecajbsi.getOznaka());
						valuta.setReferent(sessionContext.getCallerPrincipal()
								.getName());
						valuta.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
						valuteBean.zapisiValuto(valuta);
						steviloZapisanihValut++;
						logger.fine("Valuta zapisana "
								+ valuta.getOznakaValute());
					}

					TecajID tecajID = new TecajID();
					tecajID.setSifraVrsteTecajnice(vrstaTecajniceBSi
							.getSifraVrsteTecajnice());
					tecajID.setSifraValute(valuta.getSifraValute());
					tecajID.setDatumTecajnice(tecajnicaID.getDatumTecajnice());

					Tecaj tecaj = tecajniceBean.vrniTecaj(tecajID);
					if (tecaj == null) {
						logger.fine("Tečaj še ne obstaja. Pripravljam nov tečaj.");
						tecaj = new Tecaj();
						tecaj.setId(tecajID);
						tecaj.setDatumCasSpremembe(new Date());
						tecaj.setEnotaTecaja(new BigDecimal(1));
						tecaj.setSrednjiTecaj(tecajbsi.getValue());
						if (tecaj.getSrednjiTecaj() == null)
							throw new NapakaPriPrevzemu(
									"Vrednost tečaja je null");
						tecaj.setReferent(sessionContext.getCallerPrincipal()
								.getName());
						tecaj.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
						tecaj.setTecajnica(tecajnica);
						tecaj.setValuta(valuta);
						steviloNovoZapisanihTecajev++;
						logger.fine("Zapisujem tečaj za valuto "
								+ tecaj.getValuta().getOznakaValute());
						tecajniceBean.zapisiTecaj(tecaj);
					} else if (tecaj.getSrednjiTecaj().compareTo(
							tecajbsi.getValue()) != 0) {
						logger.fine("Vrednost obstoječega tečaja se razlikuje od prevzete vrednosti.");
						tecaj.setSrednjiTecaj(tecajbsi.getValue());
						logger.fine("Posodabljam tečaj na novo vrednost");
						tecajniceBean.posodobiTecaj(tecaj);
						steviloPosodobljenihTecajev++;
					}

				}

			}

			logger.info("Prevzem celotnega arhiva tečajnic BSi uspešno zaključen."
					+ " Stevilo tecajnic v arhivu: "
					+ steviloTecajnicVArhivuBSi
					+ " Stevilo novo zapisanih tecajnic: "
					+ steviloNovoZapisanihTecajnic
					+ " Stevilo tecajev v arhivu: "
					+ steviloTecajevVArhivu
					+ " Stevilo novo zapisanih tecajev: "
					+ steviloNovoZapisanihTecajev
					+ " Stevilo posodobljenih tecajev: "
					+ steviloPosodobljenihTecajev
					+ " Stevilo zapisanih valut: " + steviloZapisanihValut);

			return seznamPrevzetihTecajnic;
		} catch (Exception e) {
			logger.severe("Napaka pri prevzemu." + e.getMessage());
			throw new NapakaPriPrevzemu(e);
		}
	}
}
